﻿using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;

namespace DimensionsHelper.LanguageService.Syntax;

/// <summary>
///     文本节点的基础接口。
/// </summary>
public interface ITextNode : ITextRange
{
    /// <summary>
    ///     获取此节点的类型
    /// </summary>
    SyntaxKinds Kind { get; }


    /// <summary>
    ///     此节点的父节点，可能是<see langword="null" />
    /// </summary>
    ITextNode? Parent { get; }


    /// <summary>
    ///     获取此节点前的注释
    /// </summary>
    SyntaxComment? GetLeadingComment();


    /// <summary>
    ///     获取此节点后的注释
    /// </summary>
    SyntaxComment? GetTrailingComment();


    /// <summary>
    ///     获取所有位于当前文本节点前的注释列表
    /// </summary>
    ImmutableArray<SyntaxComment> GetLeadingComments();


    /// <summary>
    ///     获取所有位于当前文本节点后的注释列表
    /// </summary>
    /// <returns></returns>
    ImmutableArray<SyntaxComment> GetTrailingComments();


    /// <summary>
    ///     如果此节点类型是指定泛型类型，返回<see langword="true" />
    /// </summary>
    bool Is<T>([MaybeNullWhen(false)] out T node) where T : ITextNode;


    /// <summary>
    ///     如果节点是指定语法类型，返回<see langword="true" />
    /// </summary>
    bool IsNode(SyntaxKinds kind);


    /// <summary>
    ///     如果节点是指定语法类型之一，返回<see langword="true" />
    /// </summary>
    bool IsOneOfNode(params SyntaxKinds[] kinds);


    /// <summary>
    ///     查找指定类型的父节点，只返回第一个符合类型的节点。
    /// </summary>
    T? FindParent<T>() where T : ITextNode;


    /// <summary>
    ///     查找第一个回调函数返回<see langword="true"/>的父节点
    /// </summary>
    ITextNode? FindParent(Predicate<ITextNode> predicate);


    /// <summary>
    ///     <inheritdoc cref="AcceptVisitor{T}(SyntaxNodeVisitor{T})" />
    /// </summary>
    void AcceptVisitor(SyntaxNodeVisitor visitor);


    /// <summary>
    ///     使用指定的语法树访问器遍历子节点，并返回符合访问器的节点
    /// </summary>
    void AcceptVisitor<T>(SyntaxNodeVisitor<T> visitor) where T : class, ITextNode;
}


public static partial class SyntaxExtensions
{
    /// <summary>
    ///     获取文本节点区间对应的语法位置<see cref="SyntaxLocation" />。
    /// </summary>
    public static SyntaxLocation GetLocation(this ITextNode node)
    {
        return SyntaxLocation.Create(node.Uri, node.Start, node.Width);
    }
}